//
//  tdl/sys/shm.h
//
//  Created by tommy on 13/01/17.
//

#ifndef tdl_sys_shm_h
#define tdl_sys_shm_h

#include <errno.h>
#include <sys/shm.h>
#include "tdlexcept.h"
using namespace tdl;

namespace tdl {
///////////////
class shm
{
public:
	shm() : m_id(0), m_key(0), m_size(0), m_pshm(NULL) {}
	~shm() {}
	
	bool initialize(key_t shmkey, size_t shmsize) throw(shm_ex)
	{
		bool shm_exist = false;
		std::ostringstream oss;
		m_id = ::shmget(shmkey, shmsize, IPC_CREAT | IPC_EXCL | 0666);
		if(m_id < 0)
		{
			if(errno != EEXIST)
				THROW2(shm_ex, TRACE_INFO() << "shmget(" << shmkey << ", " << shmsize << ")");

			m_id = ::shmget(shmkey, shmsize, 0666);
			if(m_id < 0)
				THROW2(shm_ex, TRACE_INFO() << "shmget(" << shmkey << ", " << shmsize << ")");

			shm_exist = true;
		}
		m_pshm = ::shmat(m_id, NULL, 0);
		if((long)m_pshm < 0)
			THROW2(shm_ex, TRACE_INFO() << "shmat(" << m_id << ")");

		m_key = shmkey;
		m_size = shmsize;
		
		return shm_exist;
	}

	void detach() { ::shmdt(m_pshm); }

	void* get_p() const { return m_pshm; }

	int get_id() const { return m_id; }

	key_t get_key() const { return m_key; }

	size_t get_size() const { return m_size; }

protected:
	int			m_id;
	key_t		m_key;
	size_t		m_size;
	void*		m_pshm;
};

//////////////
}

#endif

